﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Reflection.Emit;

namespace CoolERP_Common
{
    public static class EnumHelper
    {
        /// <summary>
        /// 将一个或多个枚举常数的名称或数字值的字符串表示转换成等效的枚举对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        public static T GetValueByName<T>(string name)
        {
            if (!typeof(T).IsEnum)
                throw new ArgumentException();

            return (T)Enum.Parse(typeof(T), name);
        }

        /// <summary>
        /// 根据枚举类型创建一组 ValueTextItem，该 ValueTextItem 中的 Value 为枚举常数， Text 为枚举值的说明
        /// </summary>
        /// <param name="enumType"></param>
        /// <param name="iType">Value类型：0->int，1->string（键名称）</param>
        /// <returns></returns>
        public static ValueTextItem[] CreateValueTextItem(Type enumType, int iType)
        {
            if (!enumType.IsEnum)
                throw new ArgumentException();

            List<ValueTextItem> valueTextItems = new List<ValueTextItem>();

            foreach (string name in Enum.GetNames(enumType))
            {
                string value = Enum.Format(enumType, Enum.Parse(enumType, name), "D");
                if (iType == 1)
                    value = name;
                valueTextItems.Add(new ValueTextItem(value, GetDescriptionByName(enumType, name)));
            }
            return valueTextItems.ToArray();
        }

        /// <summary>
        /// 根据枚举类型和常数名称，获取对应的说明
        /// </summary>
        /// <param name="enumType">枚举类型</param>
        /// <param name="name">常数名称</param>
        /// <returns></returns>
        public static string GetDescriptionByName(Type enumType, object name)
        {
            if (!enumType.IsEnum)
                throw new ArgumentException();

            DescriptionAttribute da = Attribute.GetCustomAttribute(enumType.GetField(name.ToString()), typeof(DescriptionAttribute)) as DescriptionAttribute;
            if (da != null)
                return da.Description;
            else
                return "";
        }

        /// <summary>
        /// 动态创建枚举类型
        /// </summary>
        /// <param name="assemblyName">程序集名称</param>
        /// <param name="enumList">枚举类型列表</param>
        public static void DynamicCreateEnum(string assemblyName, Dictionary<string, object> enumList)
        {
            // Get the current application domain for the current thread. 获取当前应用程序
            AppDomain currentDomain = AppDomain.CurrentDomain;

            // Create a dynamic assembly in the current application domain, and allow it to be executed and saved to disk.
            // 创建一个程序集并保存在当前根目录下的Bin文件里
            AssemblyName aName = new AssemblyName(assemblyName);
            AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave, currentDomain.RelativeSearchPath);

            // Define a dynamic module in "CoolERP_Enum" assembly. For a single-module assembly, the module has the same name as the assembly.
            ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

            foreach (var enumName in enumList.Keys)
            {
                // Define a public enumeration with the name "Elevation" and an underlying type of Integer. 定义一个枚举类型
                EnumBuilder eb = mb.DefineEnum(enumName, TypeAttributes.Public, typeof(int));

                // Define members 定义枚举字段
                Type myType = typeof(DescriptionAttribute);
                ConstructorInfo myConstructorInfo = myType.GetConstructor(new Type[1] { typeof(string) });
                int i = 1;
                //将存放在enumList里的键值转换为字段集合
                Dictionary<string, string> dc = (Dictionary<string, string>)enumList[enumName];
                foreach (var key in dc.Keys)
                {
                    CustomAttributeBuilder attribute = new CustomAttributeBuilder(myConstructorInfo, new object[1] { dc[key] });
                    FieldBuilder myField = eb.DefineLiteral(key, i);
                    myField.SetCustomAttribute(attribute);
                    i++;
                }
                // Create the type and save the assembly.
                eb.CreateType();
            }
            ab.Save(aName.Name + ".dll");
        }
    }
}
